﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace Dne.GridExt.Models
{
    public static class ModelExtension
    {

        public static IList<T> Pager<T>(this IList<T> items, int rows, int page)
        {
            int startIndex = rows * (page - 1);
            var dataRangeIsNotInBound = items.Count > 0 && items.Count < startIndex;
            if (dataRangeIsNotInBound)
            {
                if (startIndex < 0)
                    startIndex = 0;
                else if (startIndex > items.Count)
                {
                    if (items.Count > rows)
                        startIndex = items.Count - rows - 1;
                    else
                        startIndex = 0;
                }
            }
            var itemCountInPage = rows;
            if (items.Count < startIndex + rows)
                itemCountInPage = items.Count % rows;
            return items.ToList().GetRange(startIndex, itemCountInPage);
        }

        public static object GridPaging<T>(GridModel model, IList<T> items, Func<T, string[]> cellSelector, Func<T, object> idSelector)
        {
            int startIndex = model.rows * (model.page - 1);
            var dataRangeIsNotInBound = items.Count > 0 && items.Count < startIndex;
            if (dataRangeIsNotInBound)
            {
                if (startIndex < 0)
                    startIndex = 0;
                else if (startIndex > items.Count)
                {
                    if (items.Count > model.rows)
                        startIndex = items.Count - model.rows - 1;
                    else
                        startIndex = 0;
                }

            }
            var itemCountInPage = model.rows;
            if (items.Count < startIndex + model.rows)
                itemCountInPage = items.Count % model.rows;
            var totalPagesCount = Math.Ceiling(items.Count / (double)model.rows);
            var pagedRows = items.ToList().GetRange(startIndex, itemCountInPage);

            var resultRows =
                pagedRows.Select(x => new
                {
                    id = idSelector(x),
                    cell = cellSelector(x)
                });

            var jsonData = new
            {
                total = totalPagesCount,
                page = model.page,
                records = items.Count(),
                rows = resultRows
            };
            return jsonData;
        }

        public static object GridPagingSorting<T>(GridModel model, IList<T> items, Func<T, string[]> cellSelector, Func<T, object> idSelector)
        {
            int startIndex = model.rows * (model.page - 1);
            var dataRangeIsNotInBound = items.Count > 0 && items.Count < startIndex;
            if (dataRangeIsNotInBound)
            {
                if (startIndex < 0)
                    startIndex = 0;
                else if (startIndex > items.Count)
                {
                    if (items.Count > model.rows)
                        startIndex = items.Count - model.rows - 1;
                    else
                        startIndex = 0;
                }

            }
            var itemCountInPage = model.rows;
            if (items.Count < startIndex + model.rows)
                itemCountInPage = items.Count % model.rows;
            var totalPagesCount = Math.Ceiling(items.Count / (double)model.rows);

            if (!string.IsNullOrEmpty(model.sidx))
            {
                items = SortItems(model, items);
            }

            var pagedRows = items.ToList().GetRange(startIndex, itemCountInPage);

            var resultRows =
                pagedRows.Select(x => new
                {
                    id = idSelector(x),
                    cell = cellSelector(x)
                });

            var jsonData = new
            {
                total = totalPagesCount,
                page = model.page,
                records = items.Count(),
                rows = resultRows
            };
            return jsonData;
        }

        private static IList<T> SortItems<T>(GridModel model, IList<T> items)
        {
            PropertyInfo p = typeof(T).GetProperty(model.sidx);
            if (p == null)
                return items;

            Func<T, object> sortBy = x => p.GetValue(x, null);

            if (model.sord == "asc")
                items = items.OrderBy(sortBy).ToList();
            else if (model.sord == "desc")
                items = items.OrderByDescending(sortBy).ToList();

            return items;
        }

        public static IList<T> Paging<T>(this IList<T> items, int page, int itemsOnPage, out int totalPages)
        {
            int startIndex = itemsOnPage * (page - 1);
            var dataRangeIsNotInBound = items.Count > 0 && items.Count < startIndex;
            if (dataRangeIsNotInBound)
            {
                if (startIndex < 0)
                    startIndex = 0;
                else if (startIndex > items.Count)
                {
                    if (items.Count > itemsOnPage)
                        startIndex = items.Count - itemsOnPage - 1;
                    else
                        startIndex = 0;
                }

            }
            var itemCountInPage = itemsOnPage;
            if (items.Count < startIndex + itemsOnPage)
                itemCountInPage = items.Count % itemsOnPage;
            totalPages = (int)Math.Ceiling(items.Count / (double)itemsOnPage);

            return items.ToList().GetRange(startIndex, itemCountInPage);
        }
    }
}
